package example.Util;


import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;

public class UtilTest {


    /**
     * RSA2签名
     */

    public static String rsa2Sign(String privateKeyStr, String data, String charset) throws NoSuchAlgorithmException, InvalidKeySpecException {
        PrivateKey privateKey = restorePrivateKey(privateKeyStr);
        byte[] signed;

        try {
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(privateKey);
            sign.update(data.getBytes(charset));
            signed = sign.sign();
        } catch (Exception ex) {
            throw new RuntimeException("签名失败", ex);
        }

        return (StringUtils.bytesToBase64(signed));
    }

    /**
     * RSA2加密
     */


    // 最大加密字节数，超出最大字节数需要分组加密
    static int MAX_ENCRYPT_BLOCK = 117;

    public static String rsaEncrypt(String publicKeyStr, String data) throws InvalidKeySpecException, NoSuchAlgorithmException {
        PublicKey publicKey = restorePublicKey(publicKeyStr);

        int offSet = 0;
        byte[] resultBytes = new byte[0]; // 初始化为 new byte[0]
        byte[] inputArray = data.getBytes();
        int inputLength = inputArray.length;
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            while (inputLength - offSet > 0) {
                byte[] cache;
                if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK);
                    offSet += MAX_ENCRYPT_BLOCK;
                } else {
                    cache = cipher.doFinal(inputArray, offSet, inputLength - offSet);
                    offSet = inputLength;
                }
                resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
                System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
            }
            return StringUtils.bytesToBase64(resultBytes);
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RuntimeException("RSA加密失败", ex); // 抛出自定义异常或返回错误信息
        }
    }



    //region RSA2解密
    static int MAX_DECRYPT_BLOCK = 256;

    /**
     * RSA 解密
     *
     * @param privateKeyStr 私钥字符串
     * @param data          加密数据
     * @return ReturnValue
     */
    public static String rsaDecrypt(String privateKeyStr, String data) throws NoSuchAlgorithmException, InvalidKeySpecException {

        PrivateKey privateKey = restorePrivateKey(privateKeyStr);

        int offSet = 0;
        byte[] resultBytes = {};
        byte[] cache;
        byte[] inputArray;

        inputArray = Base64.getDecoder().decode(data);

        int inputLength = inputArray.length;

        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            while (inputLength - offSet > 0) {
                if (inputLength - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(inputArray, offSet, MAX_DECRYPT_BLOCK);
                    offSet += MAX_DECRYPT_BLOCK;
                } else {
                    cache = cipher.doFinal(inputArray, offSet, inputLength - offSet);
                    offSet = inputLength;
                }
                resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
                System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
            }

            return new String(resultBytes);

        } catch (Exception ex) {
            ex.printStackTrace(); // 或者使用日志记录
            return null; // 或者返回一个错误信息
        }
    }



    //region RSA2验签

    /**
     * RSA2验签
     *
     * @param publicKeyStr 公钥字符串
     * @param data         明文
     * @param sign         签名
     * @return ReturnValue
     */
    public static String verifyRSA2Sign(String publicKeyStr, String data, String sign) throws InvalidKeySpecException, NoSuchAlgorithmException {

        PublicKey publicKey = restorePublicKey(publicKeyStr);

        boolean signedSuccess;
        try {
            Signature verifySign = Signature.getInstance("SHA256withRSA");
            verifySign.initVerify(publicKey);
            verifySign.update(data.getBytes("UTF-8")); // 明确指定字符编码
            signedSuccess = verifySign.verify(Base64.getDecoder().decode(sign));
        } catch (Exception ex) {
            ex.printStackTrace();
            return "验签失败: " + ex.getMessage(); // 返回详细的错误信息
        }
        if (signedSuccess) {
            return "验签成功";
        } else {
            return "验签失败";
        }
    }


    public static PrivateKey restorePrivateKey(String privateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] privateKeyBytes;

        privateKeyBytes = Base64.getDecoder().decode(privateKeyStr);
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        PrivateKey privateKey;
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);

        KeyFactory factory;
        factory = KeyFactory.getInstance("RSA");

        privateKey = factory.generatePrivate(pkcs8EncodedKeySpec);

        return privateKey;
    }

    private static PublicKey restorePublicKey(String publicKeyStr) throws InvalidKeySpecException, NoSuchAlgorithmException {

        byte[] publicKeyBytes;

        publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);
        PublicKey publicKey;
        KeyFactory factory;
        factory = KeyFactory.getInstance("RSA");
        publicKey = factory.generatePublic(x509EncodedKeySpec);

        return publicKey;
    }






}
